﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using ChatBox.Commands;
using ChatBox.Utilities;
using ChatBox.Views;
using ChatBox.Models;

namespace ChatBox.ViewModels
{
  public class MainViewModel : ViewModelBase, IDialogServiceClient, IWeakEventListener
  {
    #region Constructors

    public MainViewModel()
      : base()
    {
      _settingsCommand = new SimpleCommand( this.SettingsHandler );
      _aboutCommand = new SimpleCommand( this.AboutHandler );
      _moveUpCommand = new SimpleCommand( this.MoveUpHandler, this.CanMoveUp );
      _moveDownCommand = new SimpleCommand( this.MoveDownHandler, this.CanMoveDown );
      _setCurrentItemCommand = new SimpleCommand<MessageRepository>( this.SetCurrentItemHandler );

      CollectionChangedEventManager.AddListener( this.Servers, this );

      ServerInfo server1 = new ServerInfo() { Address = "http://under.net", Name = "UnderNet" };
      ServerInfo server2 = new ServerInfo() { Address = "http://popalot.net", Name = "Popalot", Status = ServerStatus.Connected };

      ChannelInfo channel1 = new ChannelInfo() { Name = "#General", Server = server1 };
      ChannelInfo channel2 = new ChannelInfo() { Name = "#Quebec", Server = server1 };
      ChannelInfo channel3 = new ChannelInfo() { Name = "#General", Server = server2 };
      channel3.Status = ChannelStatus.NewMessage;
      ChannelInfo channel4 = new ChannelInfo() { Name = "#anhero", Server = server2 };
      ChannelInfo channel5 = new ChannelInfo() { Name = "#trueanhero", Server = server2 };

      server1.Channels.Add( channel1 );
      server1.Channels.Add( channel2 );
      server2.Channels.Add( channel3 );
      server2.Channels.Add( channel4 );
      server2.Channels.Add( channel5 );

      this.Servers.Add( server1 );
      this.Servers.Add( server2 );
    }

    #endregion

    #region Public Properties

    public MessageRepository CurrentItem
    {
      get
      {
        return _selectedItem;
      }
      set
      {
        if ( value != _selectedItem )
        {
          // We un-select the previously selected item.
          if ( _selectedItem != null )
          {
            ChannelInfo channel = _selectedItem as ChannelInfo;

            if ( channel != null )
            {
              channel.Server.CurrentChannel = null;
            }
            else
            {
              this.CurrentServer = null;
            }
          }

          // We set our new selected item.
          _selectedItem = value;

          if ( _selectedItem != null )
          {
            // We update the CurrentServer property.
            this.CurrentServer = _selectedItem as ServerInfo;

            // If the CurrentServer is null, it means the newly selected item is
            // a channel.
            if ( this.CurrentServer == null )
            {
              // If it's not a channel, it means there is a serious problem, so
              // we can simply do a direct cast.
              ChannelInfo channel = ( ChannelInfo )_selectedItem;

              channel.Server.CurrentChannel = channel;
            }
          }

          this.OnPropertyChanged( "CurrentItem" );
        }
      }
    }

    public ViewableCollection<ServerInfo> Servers
    {
      get
      {
        return _servers;
      }
    }

    public ServerInfo CurrentServer
    {
      get
      {
        return _currentServer;
      }
      private set
      {
        if ( value != _currentServer )
        {
          _currentServer = value;

          _moveUpCommand.OnCanExecuteActionChanged();
          _moveDownCommand.OnCanExecuteActionChanged();

          this.OnPropertyChanged( "CurrentServer" );
        }
      }
    }

    public ICommand Settings
    {
      get
      {
        return _settingsCommand;
      }
    }

    public ICommand About
    {
      get
      {
        return _aboutCommand;
      }
    }

    public ICommand MoveUp
    {
      get
      {
        return _moveUpCommand;
      }
    }

    public ICommand MoveDown
    {
      get
      {
        return _moveDownCommand;
      }
    }

    public ICommand SetCurrentItem
    {
      get
      {
        return _setCurrentItemCommand;
      }
    }

    #endregion

    #region Private Methods

    private String GetMessage()
    {
      String result = String.Empty;

      ServerInfo currentServer = this.CurrentServer;

      if ( currentServer != null )
      {
        ChannelInfo currentChannel = currentServer.CurrentChannel;

        if ( currentChannel != null )
        {
          result = currentChannel.Message;
        }
        else
        {
          result = currentServer.Message;
        }
      }

      return result;
    }

    private void Servers_CollectionChanged( ViewableCollection<ServerInfo> servers, NotifyCollectionChangedEventArgs e )
    {
      _moveUpCommand.OnCanExecuteActionChanged();
      _moveDownCommand.OnCanExecuteActionChanged();
    }

    private void SettingsHandler()
    {
      if ( this.DialogService != null )
      {
        this.DialogService.ShowDialog<SettingsView>( new SettingsViewModel() );
      }
    }

    private void AboutHandler()
    {
      if ( this.DialogService != null )
      {
        this.DialogService.ShowDialog<AboutView>( new AboutViewModel() );
      }
    }

    private void MoveUpHandler()
    {
      this.MoveServer( -1 );
    }

    private bool CanMoveUp()
    {
      return this.CurrentServer != null && this.Servers.IndexOf( this.CurrentServer ) > 0;
    }

    private void MoveDownHandler()
    {
      this.MoveServer( 1 );
    }

    private bool CanMoveDown()
    {
      int index;
      return this.CurrentServer != null && ( index = this.Servers.IndexOf( this.CurrentServer ) ) >= 0 && index < ( this.Servers.Count - 1 );
    }

    private void SetCurrentItemHandler( MessageRepository item )
    {
      this.CurrentItem = item;
    }

    private void MoveServer( int delta )
    {
      if ( this.CurrentServer != null )
      {
        int serverIndex = this.Servers.IndexOf( this.CurrentServer );

        if ( serverIndex >= 0 && serverIndex < this.Servers.Count )
        {
          int newServerIndex = serverIndex + delta;

          newServerIndex = Math.Min( this.Servers.Count - 1, Math.Max( 0, newServerIndex ) );

          delta = newServerIndex - serverIndex;

          ServerInfo serverBackup = this.CurrentServer;

          this.Servers.RemoveAt( serverIndex );
          this.Servers.Insert( newServerIndex, serverBackup );

          this.CurrentServer = serverBackup;
        }
      }
    }

    #endregion

    #region Private Variables

    private MessageRepository _selectedItem = null;

    private readonly ViewableCollection<ServerInfo> _servers = new ViewableCollection<ServerInfo>();

    private ServerInfo _currentServer = null;

    private readonly SimpleCommand _settingsCommand;

    private readonly SimpleCommand _aboutCommand;

    private readonly SimpleCommand _moveUpCommand;

    private readonly SimpleCommand _moveDownCommand;

    private readonly SimpleCommand<MessageRepository> _setCurrentItemCommand;

    #endregion

    #region IDialogServiceClient Members

    public IDialogService DialogService { get; set; }

    #endregion

    #region IWeakEventListener Members

    public bool ReceiveWeakEvent( Type managerType, object sender, EventArgs e )
    {
      bool result = false;

      if ( managerType == typeof( CollectionChangedEventManager ) )
      {
        NotifyCollectionChangedEventArgs args = e as NotifyCollectionChangedEventArgs;

        if ( args != null )
        {
          ViewableCollection<ServerInfo> servers = sender as ViewableCollection<ServerInfo>;

          if ( servers != null )
          {
            this.Servers_CollectionChanged( servers, args );

            result = true;
          }
        }
      }

      return result;
    }

    #endregion
  }
}
